一般情況下,我們建構服務時應該會想把資料儲存在後端的資料庫裡面,不管是 RDBMS 或是各種的 NoSQL,掌握資料的好處不必多說,要建立更有用的功能或是有用的分析,都來自於一點一滴累積的用戶以及用戶的資料。至於比較不重要的東西,或是 Cache 等等,則可以存在 Cookie
、LocalStorage
、SessionStorage
裡面,雖然瀏覽器清掉就會不見,但也不是太大的問題。
那在手機上呢?File、SQLite 還是其它的行動裝置上的 Storage 或許都能達到功用,但避免開發上的麻煩並跨平台應該還是我們首要的目標之一。
AsyncStorage
是唯一官方支援的儲存方式,提供非同步 Key-Value 的存取方式,在 iOS 會把小的值儲存在 Dictionary、大的值儲存在分開的檔案中,在 Android 上則會看裝置的支援狀況選用 RocksDB 或 SQLite。
對鍵設值會使用 AsyncStorage.setItem
:
static setItem(key, value, callback?)
通常我們應該會只傳前兩個參數,然後拿回一個 Promise。例如:
try {
await AsyncStorage.setItem('@MySuperStore:key', 'I like to save it.');
} catch (error) {
// 儲存錯誤
}
在使用時 key 通常會依慣例命名成 @AppName:keyName
。
取出鍵值會使用 AsyncStorage.getItem
:
static getItem(key, callback?)
通常我們不傳 Callback 來拿回 Promise:
try {
const value = await AsyncStorage.getItem('@MySuperStore:key');
if (value !== null){
// 有值!
console.log(value);
}
} catch (error) {
// 取值錯誤
}
要注意如果沒有值會拿回 null
。
移除鍵值會使用 AsyncStorage.removeItem
:
static removeItem(key, callback?)
一樣的不傳 Callback 來拿回 Promise:
try {
const value = await AsyncStorage.removeItem('@MySuperStore:key');
} catch (error) {
// 刪除錯誤
}
更詳細的內容可以參閱官方文件。
除了內建的 AsyncStorage
之外,另一個值得一看的跨平台選擇是 Realm。Realm 是完整的行動應用程式資料庫,可以在手機、平板、穿戴式裝置中執行,在 2014 年發佈了 Java、Objective-C 以及 Swift 的版本,在現今已有數以億計的裝置在使用它,而被許多相當知名的公司採用。
而他們在 2016 年二月的 React Conference 上發佈了 Realm React Native。
藉由 Data Model 跟 Schema 可以在 OOP (Object-Oriented Programming) 的基礎上寫出比 Key-Value 更好管理、更可讀的程式碼,這類似於我們在後端常用的 ORM (Object Relational Mapping):
class Car {}
Car.schema = {
name: 'Car',
properties: {
make: 'string',
model: 'string',
miles: 'int',
}
};
class Person {}
Person.schema = {
name: 'Person',
properties: {
name: { type: 'string'},
cars: { type: 'list', objectType: 'Car' },
picture: { type: 'data', optional: true }, // optional property
}
};
// 取得 Realm 支援這些 Schema 的 物件
let realm = new Realm({ schema: [Car, Person] });
已經查詢過的結果會根據改變自己 Reactive 的更新:
let hondas = realm.objects('Car').filtered('make = "Honda"');
// hondas.length == 0
realm.write(() => {
realm.create('Car', {make: 'Honda', model: 'RSX'});
});
// hondas.length == 1
也可以直接地去監聽改變:
realm.objects('Dog').filtered('age < 2').addListener((puppies, changes) => {
// Do something...
});
雖然 Realm 提供了很高的易用性,而且還有以物件為主的 API,但並不因此損害效能,甚至在一般情況下效能都遠勝 SQLite 和 AsyncStorage。
詳細的內容也可以參閱 Realm 的 React Native 文件。
本文所提到的都是筆者覺得可用性、穩定性較為高的方案,小的一些資料直接使用內建的 AsyncStorage 來存是最簡單的,比較多而且有結構的資料使用 Realm 來存也很不錯。長遠下來說不定還會有其他的東西進到 React Native 的核心,不過目前這樣也沒什麼太大的問題。